﻿/*
  WcfClientBase contains a simple base class that encapsulates WCF service calls.

WcfClientBase introduces an abstract class that handles creating a service client, making the call, closing the channel or aborting it if any exceptions occur. You can also extend exception handling mechanism. At the moment, it doesn't support asynchronous calls. It's thread safe, it can be used with singleton life-cycle to make successive service calls.
  一个抽象类，可以创建一个服务客户，打电话，关闭通道或中止它是否有异常发生。你还可以扩展的异常处理机制。目前，它不支持异步调用。它是线程安全的，它可用于单周期使连续服务电话。
 */

/*
 * //MemberServiceClient is the class generated by SvcUtil
public class MemberServiceManager : ServiceClientBase<MemberServiceClient>
{

    //makes a call to GetUsername operation, closes the channel and handles the exceptions
    //you may want to implement another base class for overriding exception handling methods
    //return value will be default of return type if any exceptions occur
    public string GetUsername(int userId)
    {
        return PerformServiceOperation(client => client.GetUserTypeFromProfileID(userId));
    }

    //or you can manually check if any exceptions occured with this overload
    public bool TryGetUsername(int userId, out string username)
    {
        return TryPerformServiceOperation(client => client.GetUserTypeFromProfileID(userId), out username);
    }

}
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;

namespace WinnerCMS.Common.Wcf
{
    /// <summary>
    /// Provides the base implementation used to open, close and abort service channels and provides
    /// callbacks to handle exceptions.
    /// </summary>
    /// <typeparam name="TServiceClient">The type that is identified as ServiceClient generated by WCF</typeparam>
    public abstract class ServiceClientBase<TServiceClient> where TServiceClient : ICommunicationObject, new()
    {
        /// <summary>
        /// Optional timeout value for closing channel
        /// </summary>
        protected TimeSpan? CloseTimeout { get; set; }

        /// <summary>
        /// Initializes a new instance of the TServiceClient using parameterless constructor.
        /// Override if you need to use one of the other constructors.
        /// Called before every service operation.
        /// </summary>
        protected virtual TServiceClient InitializeServiceClient()
        {
            return new TServiceClient();
        }


        /// <summary>
        /// Generic method for initializing ServiceClient, performing service operation, closing the channel or 
        /// handling the exception and aborting the channel.
        /// </summary>
        /// <param name="serviceCall">Callback for assigning service operation response</param>
        private void HandleServiceCall(Action<TServiceClient> serviceCall)
        {
            TServiceClient serviceClient = InitializeServiceClient();


            try
            {
                serviceCall.Invoke(serviceClient);

                if (CloseTimeout.HasValue)
                {
                    serviceClient.Close(CloseTimeout.Value);
                }
                else
                {
                    serviceClient.Close();
                }
            }
            catch (FaultException exception)
            {
                serviceClient.Abort();
                HandleFaultException(exception);
            }
            catch (CommunicationException exception)
            {
                serviceClient.Abort();
                HandleCommunicationException(exception);
            }
            catch (TimeoutException exception)
            {
                serviceClient.Abort();
                HandleTimeoutException(exception);
            }


        }


        /// <summary>
        /// Performs a service operation and returns the response from that operation.
        /// </summary>
        /// <typeparam name="TResponse">Service operation return type</typeparam>
        /// <param name="serviceMethod">Service method call</param>
        /// <returns></returns>
        protected TResponse PerformServiceOperation<TResponse>(Func<TServiceClient, TResponse> serviceMethod)
        {
            TResponse result = default(TResponse);
            HandleServiceCall(item => result = serviceMethod.Invoke(item));


            return result;
        }


        /// <summary>
        /// Performs a service operation that does not return anything.
        /// </summary>
        /// <param name="serviceMethod">Service method call</param>
        protected void PerformServiceOperation(Action<TServiceClient> serviceMethod)
        {
            HandleServiceCall(serviceMethod);
        }


        /// <summary>
        /// Tries to perform a service operation and return the response from that operation.
        /// Returns false if an exception is thrown.
        /// </summary>
        /// <typeparam name="TResponse">Service operation return type</typeparam>
        /// <param name="serviceMethod">Service method call</param>
        /// <param name="result">Result that was returned from the service
        /// Default of TResponse if operation failed.</param>
        /// <returns></returns>
        protected bool TryPerformServiceOperation<TResponse>(Func<TServiceClient, TResponse> serviceMethod, out TResponse result)
        {
            bool isOperationSuccessful = false;
            TResponse serviceResponse = default(TResponse);


            HandleServiceCall(item =>
            {
                serviceResponse = serviceMethod.Invoke(item);
                isOperationSuccessful = true;
            });

            result = serviceResponse;
            return isOperationSuccessful;
        }


        /// <summary>
        /// Tries to perform a service operation that does not return anything.
        /// IsOperationSuccessful is false if an exception is thrown.
        /// </summary>
        /// <param name="serviceMethod">Service method call</param>
        /// <returns></returns>
        protected bool TryPerformServiceOperation(Action<TServiceClient> serviceMethod)
        {
            bool result = false;


            HandleServiceCall(item =>
            {
                serviceMethod.Invoke(item);
                result = true;
            });


            return result;
        }


        /// <summary>
        /// Method for handling FaultException
        /// </summary>
        /// <param name="exception">Exception that was thrown by the ServiceClient</param>
        protected virtual void HandleFaultException(FaultException exception)
        {
            throw exception;
        }


        /// <summary>
        /// Method for handling CommunicationException
        /// </summary>
        /// <param name="exception">Exception that was thrown by the ServiceClient</param>
        protected virtual void HandleCommunicationException(CommunicationException exception)
        {
            throw exception;
        }


        /// <summary>
        /// Method for handling TimeoutException
        /// </summary>
        /// <param name="exception">Exception that was thrown by the ServiceClient</param>
        protected virtual void HandleTimeoutException(TimeoutException exception)
        {
            throw exception;
        }


    }

}
